/**
 *
gcc -Wall dict.c myregex.c regex.c -lm -D_DEBUG_ -DSTDC_HEADERS && a
gcc -Wall dict.c myregex.c regex.c -lm -D_DEBUG_ -DSTDC_HEADERS -o ~/a && ~/a
 */

#include "myregex.h"

char * buff_resize(char*buf,int tolen)
{
	if(tolen>0){
		//printf("tolen:%d\n",tolen);
		char *ret;
		if(buf){
			ret = (char*)realloc(buf,tolen);
			//memset(ret+strlen(ret),0,tolen-strlen(ret));
			return ret;
		}
		ret = (char*)malloc(tolen);
		memset(ret,0,tolen);
		return ret;
	}
	return buf;
}
char * buff_apend_str(char*buf,int *buf_len,char * s)
{
	if(s == NULL)return buf;
	if(buf == NULL){
		*buf_len = strlen(s);
		buf = (char*)malloc(*buf_len);
		memset(buf,0,*buf_len);
	}
	//printf("buf_len:%d,%d\n",*buf_len,strlen(buf));
	if(*buf_len < strlen(buf) + strlen(s) + 1)
	{
		int len = strlen(buf)>*buf_len?strlen(buf):*buf_len;
		*buf_len = strlen(s) + len + 1;
		buf = (char*)realloc(buf,*buf_len);
		//memset(buf+strlen(buf),0,*buf_len-strlen(buf));
	}
	int _len = strlen(buf);
	int len = sprintf(buf+_len,s);
	buf[len+_len] = '\0';
	return  buf;
}

int regex_match(const char*s,const char*reg)
{/*{{{*/
	int err;
	regex_t re;            
	char          errbuf [EBUFLEN];
	regmatch_t    subs [SUBSLEN];
	err = regcomp(&re, reg, REG_EXTENDED);
	if (err)
	{
		regerror(err, &re, errbuf, sizeof(errbuf));
		printf("error: %s\n", errbuf);
		return 0;
	}
	err = regexec(&re, s, (size_t) SUBSLEN, subs, 0);
	if (err == REG_NOMATCH)
	{
		printf("no matched\n");
		regfree(&re);
		return 0;
	}else if (err){  
		regerror(err, &re, errbuf, sizeof(errbuf));
		printf("error: %s\n", errbuf);
		regfree(&re);
		return 0;
	}
	//printf("regex_match: %d\n", re.re_nsub);
	regfree(&re);
	return 1;
}/*}}}*/


/**
 *  
 *
 * @param s	the string to search
 * @param reg	the regex
 * @param callback	0:the first matched,
 * 					1:the first submatch,
 * 					2:the second submatch,
 * 					3:the third submatch,
 * 					...
 *
 * @return  
 */
char *regex_search(char * s,char * reg , int callback,int *dealed_len)
{/*{{{*/
	size_t       len;
	regex_t       re;            
	regmatch_t    subs [SUBSLEN];
	char*matched = (char*)malloc(strlen(s));    
	char          errbuf [EBUFLEN];
	int           err;
	if(dealed_len)*dealed_len = 0;

	//printf("String	: %s,len:%d\n", s,strlen(s));
	//printf("Pattern	: \"%s\"\n", reg);

	err = regcomp(&re, reg, REG_EXTENDED);
	if (err)
	{
		len = regerror(err, &re, errbuf, sizeof(errbuf));
		printf("error: %s\n", errbuf);
		if(dealed_len) *dealed_len = strlen(s);
		regfree(&re);
		return "";
	}

	//printf("re.re_nsub: %d\n", re.re_nsub);
	char *subsrc = s;
	if(dealed_len) subsrc += *dealed_len;
	err = regexec(&re, subsrc, (size_t) SUBSLEN, subs, 0);
	if (err == REG_NOMATCH)
	{
		//printf("Sorry, no more match ...\n");
		if(dealed_len) *dealed_len = strlen(s);
		regfree(&re);
		return "";
	}else if (err){  
		len = regerror(err, &re, errbuf, sizeof(errbuf));
		//printf("error: %s\n", errbuf);
		if(dealed_len) *dealed_len = strlen(s);
		regfree(&re);
		return "";
	}

	callback = (callback>re.re_nsub?re.re_nsub:callback);
	len = subs[callback].rm_eo - subs[callback].rm_so;
	memcpy (matched, subsrc + subs[callback].rm_so, len);
	matched[len] = '\0';
	if(dealed_len)
		*dealed_len += subs[0].rm_eo;//当前匹配的结束地址
	regfree(&re);
	return matched;
}/*}}}*/

/* -----------------------------------------------*/
/**
 *  replace the string with the call back search string array 
 *
 * @param str
 * @param str_arr
 * @param arr_len
 *
 * @return  
 */
char *regex_replace2(char * str,const char ** str_arr , int arr_len)
{
	size_t       len;
	regex_t       re;            
	regmatch_t    subs [SUBSLEN];
	char          matched[8];
	char          errbuf [EBUFLEN];
	int           err, i,pos=0;
	char          pattern [] = "\\\\[0-9]{1,2}";
	int retbufsize = 0;
	char *ret=NULL;

	//printf("String	: %s\nlen:%d\n", str,strlen(str));
	//printf("Pattern	: %s \n", pattern);

	err = regcomp(&re, pattern, REG_EXTENDED);
	if (err)
	{
		len = regerror(err, &re, errbuf, sizeof(errbuf));
		//printf("error: %s\n", errbuf);
		return str;
	}

	//printf("re.re_nsub: %d\n", re.re_nsub);
	do{
		char *subsrc = str+pos;
		err = regexec(&re, subsrc, (size_t) SUBSLEN, subs, 0);
		if (err == REG_NOMATCH)
		{
			//printf("Sorry, no more match ...\n");
			break;
		}else if (err){  
			len = regerror(err, &re, errbuf, sizeof(errbuf));
			//printf("error: %s\n", errbuf);
			break;
		}

		len = subs[0].rm_eo - subs[0].rm_so;
		//printf ("first match : %d -> %d , len : %d , ",pos + subs[i].rm_so,pos + subs[i].rm_eo,len);

		memcpy(matched, subsrc + subs[0].rm_so, len);
		matched[len] = '\0';
		//printf("match: %s\n", matched);
		i = atoi(matched+1);
		if(i<arr_len){
			char * replace_str = (char*)(str_arr[i]);
			//printf("[%d]=%s\n",i,replace_str);
			retbufsize += (subs[0].rm_so+1);
			//printf("retbufsize:%d\n",retbufsize);
			ret = buff_resize(ret,retbufsize);
			//printf("[%d]=%s\n",i,replace_str);
			int _len = strlen(ret);
			memcpy(ret+_len, subsrc, subs[0].rm_so);
			ret[_len+subs[0].rm_so]='\0';
			ret = buff_apend_str(ret,&retbufsize,(char*)replace_str);
			pos += subs[0].rm_eo;//当前匹配的结束地址
			//printf("cur pos:%d\n",pos);
		}else{
			return str;
		}
	}while(pos < strlen(str));

	if(strlen(str)>pos){
		ret = buff_apend_str(ret,&retbufsize,str+pos);
	}
	regfree(&re);

	return ret;
}
/**
 *  
 *
 * @param s
 * @param reg
 * @param replace_str	replace the matched string with the replace_str
 *
 * @return  
 */
char *regex_replace(char * s, const char * reg , const char * replace_str,int *dealed_len)
{/*{{{*/
	size_t       len;
	regex_t       re;            
	regmatch_t    subs [SUBSLEN];
	char          errbuf [EBUFLEN];
	int           err, i;
	if(dealed_len) *dealed_len = 0;
	int bufsize= 0;
	char *ret = NULL;

	//printf("String	: %s (len:%d)\n", s,strlen(s));
	//printf("Pattern	: %s \n", reg);
	//printf("replace with str : %s \n", replace_str);

	err = regcomp(&re, reg, REG_EXTENDED);
	if (err)
	{
		len = regerror(err, &re, errbuf, sizeof(errbuf));
		//printf("error: %s\n", errbuf);
		if(dealed_len) *dealed_len = strlen(s);
		return s;
	}

	//printf("re.re_nsub: %d\n", re.re_nsub);
	do{
		char *subsrc = s;
		if(dealed_len)
			subsrc += *dealed_len;
		err = regexec(&re, subsrc, (size_t) SUBSLEN, subs, 0);
		if (err == REG_NOMATCH)
		{
			//printf("Sorry, no more match ...\n");
			break;
		}else if (err){  
			len = regerror(err, &re, errbuf, sizeof(errbuf));
			//printf("error: %s\n", errbuf);
			if(ret)free(ret);
			if(dealed_len) *dealed_len = strlen(s);
			return s;
		}

		char **matched=(char**)malloc(sizeof(char**)*(re.re_nsub+2));    
		for (i = 0; i <= re.re_nsub; i++)
		{
			len = subs[i].rm_eo - subs[i].rm_so;
			//printf("a[%d]len:%d",i,len);
			matched[i] = (char*)malloc(len+1);
			memcpy ((char*)matched[i], subsrc + subs[i].rm_so, len);
			matched[i][len] = '\0';
			//printf("match: %s\n", (char*)matched[i]);
		}
		char * copy_str = NULL;
		bufsize += (subs[0].rm_so+1);
		//printf("0ret:%s\n",ret);
		ret = buff_resize(ret,bufsize);
		//printf("1ret:%s\n",ret);
		int _len = strlen(ret);
		memcpy (ret+_len, subsrc, subs[0].rm_so);
		ret[_len+subs[0].rm_so] = '\0';
		if(re.re_nsub>0 && regex_match(replace_str,"\\\\[0-9]{1,2}")>0){//替换字符串中含有回调,回调号功能
			//printf("----------------------------------------------------------------------------------\n");
			//fflush(stdout);
			copy_str = regex_replace2((char*)replace_str, (const char**)matched, re.re_nsub+1);
			//printf("copy_str:%s\n",copy_str);
			if(copy_str && strlen(copy_str)>0){
				ret = buff_apend_str(ret,&bufsize,copy_str);
				if(copy_str != replace_str){
					free(copy_str);
					copy_str = NULL;
				}
			}
		}else{
			ret = buff_apend_str(ret,&bufsize,(char*)replace_str);
		}
		//printf("replaced str: %s,%s,%d\n",ret,replace_str,re.re_nsub);
		/*
		   for (i = 0; i <= re.re_nsub; i++)
		   {
		   if(matched[i]) free(matched[i]);
		   matched[i]=NULL;
		   }
		   */
		free(matched);matched = NULL;
		if(dealed_len)
			*dealed_len += subs[0].rm_eo;//当前匹配的结束地址
		else
			break;
	}while(*dealed_len < strlen(s));

	if(dealed_len){
		if(strlen(s)>(int)(*dealed_len)) 
			ret = buff_apend_str(ret,&bufsize, s + (*dealed_len));
	} else {
		ret = buff_apend_str(ret,&bufsize, s + subs[0].rm_eo);
	}

	regfree(&re);
	//printf("result:%s\n",ret);
	return ret;
}/*}}}*/
int regex_search_all(char * s,char * reg , char **matched_arr)
{
	int num = 0;
	int dealed_len=0;
	int pos = 0;
	while(pos<strlen(s))
	{
		char * p = s + pos;
		matched_arr[num] = regex_search(p,reg , 0,&dealed_len);
		if(matched_arr && strlen(matched_arr[num])>0){
			printf(" matched:%s,dealed_len:%d\n",matched_arr[num],pos);
			//free(matched_arr[num]); matched_arr[num]=NULL;
			++num;
		}else{
			break;
		}
		pos += dealed_len; 
	}

	return num;
}

char *regex_replace_all(char * s, const char * reg , const char * replace_str)
{
	int dealed_len=0;
	return  regex_replace(s,reg,replace_str,&dealed_len);
}

#ifdef _DEBUG_
int main()
{/*{{{*/
	size_t       len;
	regex_t       re;            
	regmatch_t    subs [SUBSLEN];
	char          *matched;
	char          errbuf [EBUFLEN];
	int           err, i,pos=0;
	char          src    [] = "start <title> Hello World 1</title> end";
	char          pattern [] = "<[^<>]+>([^<>]+) ([^<>]+)</[^<>]+>";
	matched = (char*)malloc(strlen(src));

	printf("\nString	: %s\nlen:%d\n", src,strlen(src));
	printf("Pattern	: %s \n", pattern);

	printf(regex_replace_all(src,"<([^<>]+)>","-\\1-"));
	printf("\n-----------\n");


	printf("\ntest regex_search_all:\n");
	char **matched_arr=(char**)malloc(sizeof(char*)*strlen(src));
	len = regex_search_all(src,"<([^<>]*)>",matched_arr);
	printf("%d\n",len);
	for(i=0;i<len;++i) {
		if(matched_arr[i])
		{
			free(matched_arr[i]);
			matched_arr[i] = 0;
		}
	}
	if(matched_arr)
		free(matched_arr);

	printf("\ntest regex_search:\n");
	int dealed_len;
	char *replaced = regex_search(src,pattern,0,&dealed_len);
	printf("%s,%d",replaced,dealed_len);
	if(src != replaced)free(replaced);//free
	printf("\n-----------\n");

	printf("\ntest regex_replace:\n");
	replaced = regex_replace(src,pattern,"test \\1 test",&dealed_len);
	printf("%s,%d",replaced,dealed_len);
	if(src != replaced)free(replaced);//free
	printf("\n-----------\n");

	err = regcomp(&re, pattern, REG_EXTENDED);
	if (err)
	{
		len = regerror(err, &re, errbuf, sizeof(errbuf));
		printf("error: %s\n", errbuf);
		return 1;
	}

	//printf("re.re_nsub: %d\n", re.re_nsub);
	do{
		char *subsrc = src+pos;
		err = regexec(&re, subsrc, (size_t) SUBSLEN, subs, 0);
		if (err == REG_NOMATCH)
		{
			printf("Sorry, no more match ...\n");
			break;
		}else if (err){  
			len = regerror(err, &re, errbuf, sizeof(errbuf));
			printf("error: %s\n", errbuf);
			break;
		}

		for (i = 0; i <= re.re_nsub; i++)
		{
			len = subs[i].rm_eo - subs[i].rm_so;
			if (i == 0)
			{//当前匹配
				printf ("first match : %d -> %d , len : %d , ",pos + subs[i].rm_so,pos + subs[i].rm_eo,len);
			}
			else
			{//子匹配
				printf("sub match %d : %d -> %d , len : %d , ", i, pos + subs[i].rm_so,pos + subs[i].rm_eo, len);
			}

			memcpy (matched, subsrc + subs[i].rm_so, len);
			matched[len] = '\0';
			printf("match: %s\n", matched);
		}
		pos += subs[0].rm_eo;//当前匹配的结束地址
		printf("cur pos:%d\n",pos);
	}while(pos < strlen(src));

	regfree(&re);
	return (0);
}/*}}}*/
#endif
